package org.example.learn.javaagent.bytebuddy;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;

// Byte-Buddy 实现监控方法耗时
public class ByteBuddyAgent {

    public static void premain(String agentArgs, Instrumentation inst){
        System.out.println("agentArgs: " + agentArgs);

        // 转换器允许对DynamicType应用修改。 然后将这种修改应用于与前面的匹配器匹配的任何检测类型
        AgentBuilder.Transformer transformer = (builder,typeDescription,classLoader,javaModule) -> {
            return builder.method(ElementMatchers.any())
                    .intercept(MethodDelegation.to(MethodCostTime.class));
        };

        // 监听器 监听检测过程中发生的事件
        AgentBuilder.Listener listener = new AgentBuilder.Listener() {

            // 转换类型时调用
            @Override
            public void onDiscovery(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {

            }

            // 在成功应用转换之前调用。
            @Override
            public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded, DynamicType dynamicType) {

            }

            //当类型未转换但被忽略时调用
            @Override
            public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded) {

            }

            //在转换过程中发生错误时调用。
            @Override
            public void onError(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded, Throwable throwable) {

            }

            //在尝试加载类后调用，与其处理无关。
            @Override
            public void onComplete(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {

            }
        };

        new AgentBuilder.Default()
                // 指定需要拦截类所在的包 匹配器 匹配规则（匹配正在加载的类型）
                .type(ElementMatchers.nameStartsWith("org.example.learn.javaagent.bytebuddy"))
                // 为匹配器 指定 转换器
                .transform(transformer)
                // 添加监听器 若一个监听器被添加两次，则会通知两次
                .with(listener)
                // 装填 Instrumentation 并返回一个 ResettableClassFileTransformer
                // installOn(inst) 方法说明
                //创建并安装一个ResettableClassFileTransformer ，它使用给定的Instrumentation实现此代理构建器的配置。 如果启用重新转换，安装还会导致所有加载的类型重新转换。
                //为了确保正确处理AgentBuilder.InstallationListener ，应通过ResettableClassFileTransformer的reset方法应用卸载。
                .installOn(inst);
    }

    public static void premain(String agentArgs){

    }
}
